import static com.googlecode.javacv.cpp.opencv_core.CV_TERMCRIT_ITER;
import static com.googlecode.javacv.cpp.opencv_core.cvAnd;
import static com.googlecode.javacv.cpp.opencv_core.cvGetSize;
import static com.googlecode.javacv.cpp.opencv_core.cvLoad;
import static com.googlecode.javacv.cpp.opencv_core.cvReleaseImage;
import static com.googlecode.javacv.cpp.opencv_imgproc.CV_BGR2HSV;
import static com.googlecode.javacv.cpp.opencv_imgproc.CV_THRESH_BINARY;
import static com.googlecode.javacv.cpp.opencv_imgproc.cvCvtColor;
import static com.googlecode.javacv.cpp.opencv_imgproc.cvThreshold;
import static com.googlecode.javacv.cpp.opencv_video.cvCamShift;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

import javax.media.Time;
import javax.swing.BorderFactory;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import com.googlecode.javacv.CanvasFrame;
import com.googlecode.javacv.OpenCVFrameGrabber;
import com.googlecode.javacv.cpp.opencv_core.*;
import com.googlecode.javacv.cpp.opencv_imgproc.CvConnectedComp;
import com.googlecode.javacv.cpp.opencv_imgproc.CvHistogram;
import com.googlecode.javacv.cpp.opencv_objdetect.CvHaarClassifierCascade;

import de.anvilsoft.AnnotationManager;
import de.anvilsoft.Anvil;
import de.anvilsoft.AnvilChangeEvent;
import de.anvilsoft.AnvilChangeListener;
import de.anvilsoft.MediaManager;
import de.anvilsoft.action.AnvilAction;
import de.anvilsoft.annot.AnnContainer;
import de.anvilsoft.annot.AnnElement;
import de.anvilsoft.annot.AnnTrack;
import de.anvilsoft.annot.AnnotationChangeListener;
import de.anvilsoft.annot.AnnotationFile;
import de.anvilsoft.annot.attribute.AnnFloatAttribute;
import de.anvilsoft.annot.attribute.AnnTimestampedPointsAttribute;
import de.anvilsoft.annot.impl.AnnPrimaryTrackImpl;
import de.anvilsoft.annot.impl.AnnProperties;
import de.anvilsoft.annot.impl.AnnProperty;
import de.anvilsoft.annot.impl.AnnStringProperty;
import de.anvilsoft.annot.impl.AnnotationFileImpl;
import de.anvilsoft.annot.impl.PrimaryIntervalElement;
import de.anvilsoft.annot.impl.TimestampedScreenPoint;
import de.anvilsoft.annot.valuetype.ValuePointsType;
import de.anvilsoft.gui.ContainerChangeEvent;
import de.anvilsoft.gui.SelectionChangeEvent;
import de.anvilsoft.gui.SelectionChangeListener;
import de.anvilsoft.gui.video.VideoMouseListener;
import de.anvilsoft.gui.video.VideoOverlayPanel;
import de.anvilsoft.media.MediaTimeChangeEvent;
import de.anvilsoft.media.MediaTimeChangeListener;
import de.anvilsoft.media.Video;
import de.anvilsoft.plugin.Plugin;

public class AnvilCamshiftPlugin extends JFrame implements Plugin, AnvilChangeListener, MediaTimeChangeListener, ActionListener, ChangeListener, AnnotationChangeListener, SelectionChangeListener, MouseListener, ItemListener{
    private Anvil main;
    // CONTROL PANEL
	private final int SAT_INIT = 35;
	private final int FRAME_INIT = 0;
	private final int MOVE_INIT = 2;
	private JSlider satSlider;
	private JSlider skipSlider;
	private JSlider moveSlider;
	private JButton startBtn;  
	private JButton pauseBtn;
	private JButton resumeBtn;
	private JButton saveBtn;
	private JCheckBox showProjWindow;
	private JCheckBox showSatWindow;
	// ANVIL STUFF
    private MediaManager mediaDelegate = null;
    private JFrame videoWindow = null;
    private Video masterVideoWindow = null;
    private VideoOverlayPanel overlayPanel = null; 
	private AnnotationManager annotationManger = null;
	private String ActiveTrack;
	private AnnPrimaryTrackImpl movementIntervalsTrack;
	private AnnotationFileImpl annotation = null;
	
	// TRACKER
	private boolean selectionChanged = false;
	private boolean trackingEnabled = false;
	
	private CanvasFrame satCanvas;
	private CanvasFrame projCanvas;
	private OpenCVFrameGrabber grabber;
	private ContentFinder finder;
	
	private Rectangle selection = null;
	private IplImage origImg;
	private BufferedImage currImg;
	private CvBox2D curBox = new CvBox2D();
	private CvRect prevWindow = new CvRect();
	
	private int satThresh = SAT_INIT;
	private int moveThresh = MOVE_INIT;
	private int frameSkip = FRAME_INIT;
	private int currentFrame;
	private int prevFrame = -1;
	// MOVEMENT
    private ValuePointsType moveVector;              
	private Point moveStartPoint;
	private Point moveEndPoint;
	private Time currentTime;
	private Time moveStartTime;
	private Time moveEndTime;
	private double moveDistance;
	private int freeFrames = 0;

    private void exit(){
	    dispose();
	    mediaDelegate.removeMediaTimeChangeListener(this);
	    main.removeSubwindow(this);
	    main.pluginExited(this);
    }

	public boolean canHaveMultipleInstances() {
	    return false;
    }

	public boolean exitFromAnvil(){
	    dispose();
	    return true;
    }
	
	public boolean startFromAnvil(Anvil main) {
		//display windows
		satCanvas = new CanvasFrame("Target saturation mask");
		projCanvas = new CanvasFrame("Back-projection with reduced saturation pixels.");
		projCanvas.setVisible(false);
		satCanvas.setVisible(false);
		
        this.main = main;
        main.addAnvilChangeListener(this);
        mediaDelegate = main.getMediaManager();
        mediaDelegate.addMediaTimeChangeListener(this);
        masterVideoWindow = mediaDelegate.getMasterVideo();         
        annotationManger = main.getAnnotationManger();

        WindowAdapter windowAdapter = new WindowAdapter(){
            public void windowClosing(WindowEvent we){
            	exit();
            }
        };
        this.addWindowListener(windowAdapter);
        initControlPanel();
        annotation = main.getAnnotationFile();
        
        if(annotation != null){
            annotation.addAnnotationChangeListener(this);
            AnnotationManager w = main.getAnnotationManger();
            w.addSelectionChangeListener(this);
            init();
        }
        
        main.addSubwindow(this);   
        return true;
    }
	
	private void initControlPanel(){
        setTitle("Tracker Controls");
        
        JPanel sliders = new JPanel();
        TitledBorder title = BorderFactory.createTitledBorder("Tracker thresholds");
        sliders.setBorder(title);     
		//saturation slider
		JLabel satLabel = new JLabel("Saturation");	
		satSlider = new JSlider(JSlider.HORIZONTAL, 0, 255, SAT_INIT);
		satSlider.addChangeListener(this);	
		satSlider.setMajorTickSpacing(20);
		satSlider.setPaintTicks(true);
		satSlider.setPaintLabels(true);	
		//frameskip slider
		JLabel skipLabel = new JLabel("Frameskip");
		skipSlider = new JSlider(JSlider.HORIZONTAL, 0, 24, FRAME_INIT);
		skipSlider.addChangeListener(this);
		skipSlider.setMajorTickSpacing(6);	
		skipSlider.setPaintTicks(true);
		skipSlider.setPaintLabels(true);
		//movement threshold slider
		JLabel moveLabel = new JLabel("Movement");
		moveSlider = new JSlider(JSlider.HORIZONTAL, 1, 10, MOVE_INIT);
		moveSlider.addChangeListener(this);
		moveSlider.setMajorTickSpacing(1);
		moveSlider.setSnapToTicks(true);
		moveSlider.setPaintTicks(true);
		moveSlider.setPaintLabels(true);
		
		GroupLayout gl = new GroupLayout(sliders);
		gl.setAutoCreateGaps(true);
        gl.setAutoCreateContainerGaps(true);
		sliders.setLayout(gl);
		gl.setHorizontalGroup(gl.createParallelGroup()
				.addGroup(gl.createSequentialGroup()
			              .addGroup(gl.createParallelGroup(GroupLayout.Alignment.LEADING)
			                  .addComponent(satLabel)
			                  .addComponent(skipLabel)
			                  .addComponent(moveLabel))
			              .addGroup(gl.createParallelGroup(GroupLayout.Alignment.LEADING)
			                  .addComponent(satSlider)
			                  .addComponent(skipSlider)
			                  .addComponent(moveSlider)))			                 
		);
		gl.setVerticalGroup(gl.createSequentialGroup()
			            .addGroup(gl.createParallelGroup()
				                  .addComponent(satLabel)
				                  .addComponent(satSlider))
			            .addGroup(gl.createParallelGroup()
				                  .addComponent(skipLabel)
				                  .addComponent(skipSlider))
				        .addGroup(gl.createParallelGroup()
				                  .addComponent(moveLabel)
				                  .addComponent(moveSlider))
		);
		
		JPanel checkboxes = new JPanel();
        title = BorderFactory.createTitledBorder("Display options");
        sliders.setBorder(title);
        GridLayout gridl = new GridLayout(2,0);
        gridl.setVgap(5);
        checkboxes.setLayout(gridl);
		//back projection window toggle
		showProjWindow = new JCheckBox("Show back-projection display");
		showProjWindow.setSelected(false);
		showProjWindow.addItemListener(this);		
		//saturation window toggle
		showSatWindow = new JCheckBox("Show saturation display");
		showSatWindow.setSelected(false);
		showSatWindow.addItemListener(this);
		checkboxes.add(showProjWindow);
		checkboxes.add(showSatWindow);
        
        JPanel buttons = new JPanel();
        GridLayout gridl2 = new GridLayout(0,4);
        gridl2.setVgap(5);
        checkboxes.setLayout(gridl2);
		startBtn = new JButton("Start");
		startBtn.addActionListener(this);
		pauseBtn = new JButton("Pause");
		pauseBtn.addActionListener(this);
		resumeBtn = new JButton("Resume");
		resumeBtn.addActionListener(this);
		saveBtn = new JButton("Save settings");
		saveBtn.addActionListener(this);
		buttons.add(startBtn);
		buttons.add(pauseBtn);
		buttons.add(resumeBtn);	
		buttons.add(saveBtn);	
        getContentPane().add(BorderLayout.NORTH, sliders);
        getContentPane().add(BorderLayout.CENTER, checkboxes);
        getContentPane().add(BorderLayout.SOUTH, buttons);
        
        pack();
        setVisible(true);
	}
	
    public void init(){
	    if (annotation != null){          
	    	annotation.addAnnotationChangeListener(this);
	        if(ActiveTrack != null){
	            AnnTrack activeTrack = annotation.getTrack(ActiveTrack);
	            if (activeTrack != null)
	                movementIntervalsTrack = (AnnPrimaryTrackImpl) activeTrack;
	            else
	                System.out.println("Cannot use track '" + ActiveTrack + "'. Tracking is disabled.");
	        }
	    }
	    moveVector = new ValuePointsType();
	    moveVector.setInterpolation(moveVector.LINEAR_INTERPOLATION);
	    moveVector.setConnection(moveVector.ARROW_CONNECTION);
	    moveVector.setLineColor(Color.WHITE);
	    moveVector.setLineSize(1);
	    moveVector.setLineTransparency(0.0f);
	    moveVector.setMarkerColor(Color.BLUE);
	    moveVector.setMarkerSize(2);
	    moveVector.setMarkerFilled(true);
    }
    
	public void getTrackSettings(){
	    System.out.println("getting track settings");
	    if(annotation != null && ActiveTrack != null){
	        AnnTrack activeTrack = annotation.getTrack(ActiveTrack);
	        if (activeTrack != null) {	            
	            try{
	                List<String> list = activeTrack.getAttributeNames();
	                if(list.contains("movement") && list.contains("velocity")){
						movementIntervalsTrack = (AnnPrimaryTrackImpl) activeTrack;
						changeSettings();
					}
					else{
						System.out.println("Track does not have suitable attributes!");
					}
	            }catch(java.lang.ClassCastException ee){
	            	System.out.println("Track does not have suitable attributes!");
	            }
	        }
	    }
    }
	
	private void changeSettings() {
        AnnProperties annProperties = annotation.getProperties();
        AnnProperty prop;
        int value;
        
        prop = annProperties.getProperty("Saturation."+ActiveTrack);
        if(prop != null) {
			value = Integer.parseInt(prop.getContent());
			satSlider.setValue(value);
        }
		else
			value = satSlider.getValue();
        satThresh = value;
		
        prop = annProperties.getProperty("Movement."+ActiveTrack);
        if(prop != null) {
 			value = Integer.parseInt(prop.getContent());
 			moveSlider.setValue(value);
         }
 		else
 			value = moveSlider.getValue();
         moveThresh = value;
         
		prop = annProperties.getProperty("Frameskip."+ActiveTrack);
		if(prop != null) {
			value = Integer.parseInt(prop.getContent());
			skipSlider.setValue(value);
		}
		else
			value = skipSlider.getValue();
		frameSkip = value;
	}
	
	private void saveSettings() {        
		if(annotation != null){
		    AnnTrack activeTrack = annotation.getTrack(ActiveTrack);
		    if (activeTrack != null) {
		        try {
		            List list = activeTrack.getAttributeNames();
		            if(list.contains("movement")|| list.contains("velocity")){
				        AnnProperties annProperties = annotation.getProperties();
						annProperties.addProperty("Saturation."+ActiveTrack,new AnnStringProperty(Integer.toString(satThresh)));
						annProperties.addProperty("Movement."+ActiveTrack,new AnnStringProperty(Integer.toString(moveThresh)));
						annProperties.addProperty("Frameskip."+ActiveTrack,new AnnStringProperty(Integer.toString(frameSkip)));
					}
	            }catch(java.lang.ClassCastException ee){
	            	System.out.println("Error: cannot get attribute names.");
	            }
	        }
		}
	}

	private void writeToTrack(Time start, Time end, Point startPoint, Point endPoint, float velocity) {
        try {
            if (movementIntervalsTrack == null)
                init();  
            PrimaryIntervalElement element = new PrimaryIntervalElement(movementIntervalsTrack, start, end);            
            //write velocity
            AnnFloatAttribute fa = new AnnFloatAttribute("velocity", velocity);
            element.setAttribute(fa);
            //write vector            
            AnnTimestampedPointsAttribute tpa = new AnnTimestampedPointsAttribute("movement", moveVector);
            tpa.addPoint(new TimestampedScreenPoint(start, startPoint.x, startPoint.y));
            tpa.addPoint(new TimestampedScreenPoint(end, endPoint.x, endPoint.y));
            element.setAttribute(tpa);
            
            movementIntervalsTrack.addElement(element);    
	            
        } catch (de.anvilsoft.annot.CantAddException e) {
            System.out.println("CantAddException");
        } catch (java.lang.NullPointerException e) {
            System.out.println("NullPointerException - track or properties not found!");
        }
	}
	
	private void startNewTracker() {
		System.out.println("Starting tracker for new object...");
		setSearchWindow();
		origImg = IplImage.createFrom(currImg);
		if(finder == null)
			finder = new ContentFinder();
		getOriginalHistogram();
		trackingEnabled = true;
		selectionChanged = false;
	}
	
	private void getOriginalHistogram() {
		ColorHistogram ch = new ColorHistogram();
		origImg.roi(toIplROI(selection));
		CvHistogram templateHueHist = ch.getHueHistogram(origImg,satThresh);
	    finder.setHistogram(templateHueHist);
	}
	
    private void setSearchWindow(){
	    prevWindow.x(selection.x);
	    prevWindow.y(selection.y);
	    prevWindow.width(selection.width);
	    prevWindow.height(selection.height);
    }
	
	private Rectangle search(IplImage img) {
		IplImage targetImage = img;
		
		//convert to HSV color space
	    IplImage hsvTargetImage = IplImage.create(cvGetSize(targetImage), targetImage.depth(), 3);
	    cvCvtColor(targetImage, hsvTargetImage, CV_BGR2HSV);
	    IplImage[] channels = ColorHistogram.splitChannels(hsvTargetImage);
	    IplImage saturationChannel = channels[1];
	    cvThreshold(saturationChannel, saturationChannel, satThresh, 255, CV_THRESH_BINARY);
	    if(satCanvas.isVisible())
	    	satCanvas.showImage(saturationChannel);
	    
	    IplImage result = finder.find(hsvTargetImage);
	    //showImage(result, "Back-projection.");

	    cvAnd(result, saturationChannel, result, null);
	    if(projCanvas.isVisible())
	    	projCanvas.showImage(result);

	    // Search termination criteria
	    CvTermCriteria termCriteria = new CvTermCriteria();
	    termCriteria.max_iter(10);
	    termCriteria.epsilon(0.01);
	    termCriteria.type(CV_TERMCRIT_ITER);

	    // Search using mean shift algorithm.
	    CvConnectedComp searchResults = new CvConnectedComp();
	    if(prevWindow.height()==0){
	    	System.out.println("ERROR at frame " + grabber.getFrameNumber());
	    }

	    int iterations = cvCamShift(result, prevWindow, termCriteria, searchResults, curBox);
	    //curBox.angle(0.0f);
	    CvRect cvr = searchResults.rect();
	    Rectangle rect = new Rectangle(cvr.x(),cvr.y(),cvr.width(),cvr.height());
	    if(iterations < 0 ) {
	    	System.out.println("Search window lost in frame " + currentFrame);
	    	detectMovement(cvr, true);
	    }
	    else
	    	detectMovement(cvr, false);
	    
	    if(searchResults.area()!=0){
	    	prevWindow.x(cvr.x());
	    	prevWindow.y(cvr.y());
	    	prevWindow.width(cvr.width());
	    	prevWindow.height(cvr.height());
	    }
	    
	    //cleanup
	    channels[0].release();
	    channels[1].release();
	    channels[2].release();
	    hsvTargetImage.release();
	    saturationChannel.release();
	    cvReleaseImage(result);
	    return rect;
	}
	
	private void detectMovement(CvRect cvr, boolean lost){
	    double horDiff = Math.abs( (prevWindow.x()+prevWindow.width()/2) - (cvr.x()+cvr.width()/2) );
	    double vertDiff = Math.abs( (prevWindow.y()+prevWindow.height()/2) - (cvr.y()+cvr.height()/2) );
	    double diagDiff = Math.sqrt(horDiff*horDiff + vertDiff*vertDiff);
	    //end of movement
	    if(moveStartPoint != null && (diagDiff <= moveThresh || lost)){
	    	if(freeFrames < 2){
	    		freeFrames++;
	    		moveDistance += diagDiff;
	    		return;
	    	}
	    	mediaDelegate.getFrameDuration();
			moveEndTime = currentTime;
			if(lost)
				moveEndPoint = new Point( (prevWindow.x()+prevWindow.width()/2) , (prevWindow.y()+prevWindow.height()/2) );
			else
				moveEndPoint = new Point( (cvr.x()+cvr.width()/2) , (cvr.y()+cvr.height()/2) );
			float velocity = 0;
			int frames = (int) ((moveEndTime.getSeconds() - moveStartTime.getSeconds())/mediaDelegate.getFrameDuration().getSeconds());
			velocity = (float) (moveDistance/frames);
			writeToTrack(moveStartTime, moveEndTime, moveStartPoint, moveEndPoint, velocity);
			moveStartPoint = null;
			moveStartTime = null;
			moveDistance = 0;
			freeFrames = 0;
	    }	    
	    //movement detected
	    else if(diagDiff > moveThresh && !lost){
		    moveDistance += diagDiff;
		    if(moveStartPoint == null){
				moveStartPoint = new Point( (cvr.x()+cvr.width()) , (cvr.y()+cvr.height()) );
				moveStartTime = currentTime;
		    }
	    }
	}
	  
	private void drawOnVideo(Rectangle rect){
        Graphics g = null;
		if (overlayPanel == null) {
	        overlayPanel = main.getVideoOverlay();
            overlayPanel.addMouseListener(this);
        }
        g  = overlayPanel.getGraphics();
	    overlayPanel.paintComponent(g);
	    overlayPanel.clearShapes(); 	
        g.setColor(Color.RED);
    	g.drawRect(rect.x, rect.y, rect.width, rect.height);
	}
	
	public void resetTracker() {
        overlayPanel = null;
        videoWindow = null;
        moveStartTime = null;
        moveStartPoint = null;
        origImg = null;
        finder = null;
		trackingEnabled = false;
		selectionChanged = false;
        startBtn.setEnabled(true);
	}
	
	private void getSelection(int event, int x, int y) {	
		//start selection
		if(event == 0)
			selection = new Rectangle(x,y,0,0);
		//finish selection
		else if(event == 1) {
			if(x > selection.x)				
				selection.width = x - selection.x;
			else{
				selection.width = selection.x - x;
				selection.x = x;
			}
			if(y > selection.y)
				selection.height = y - selection.y;
			else{
				selection.height = selection.y - y;
				selection.y = y;
			}
			System.out.println("Selection: x " + selection.x + " y "+ selection.y + " selection width " + selection.width + " , selection height " + selection.height);	        
	        drawOnVideo(selection);
	        selectionChanged = true;
		}
	}
	
    private IplROI toIplROI(Rectangle r){
        IplROI roi = new IplROI();
        roi.xOffset(r.x);
        roi.yOffset(r.y);
        roi.width(r.width);
        roi.height(r.height);
        return roi;
    }
	
    @Override
	public void annotationClosed(AnvilChangeEvent arg0) {
		resetTracker();
	}
	
	@Override
	public void annotationCreated(AnvilChangeEvent e) {
        annotationManger.addSelectionChangeListener(this);
        annotation = e.getAnnotation();
        if (annotation != null) 
            annotation.addAnnotationChangeListener(this);
	}
	
	@Override
	public void annotationLoaded(AnvilChangeEvent e) {
        AnnotationManager w = main.getAnnotationManger();
        w.addSelectionChangeListener(this);
        annotation = e.getAnnotation();
        init();
	}
	
	@Override
	public void mediaTimeChanged(MediaTimeChangeEvent e) {
		if(selectionChanged)
			startNewTracker();
		int mediaRealFrame = mediaDelegate.mapTimeToFrame(mediaDelegate.getVideoTime());
		if(currentFrame != mediaRealFrame)
			currentFrame = mediaRealFrame;
		
        currentTime = e.getTime();
        
        if (videoWindow == null) 
            videoWindow = main.getVideoWindow();
        int windowW = videoWindow.getWidth();
        int windowH = videoWindow.getHeight();
        if (windowW < 0) 
        	windowW = 0;
        if (windowH < 0) 
        	windowH = 0;

		if (overlayPanel == null) {
	        overlayPanel = main.getVideoOverlay();
            overlayPanel.addMouseListener(this);
        }  
	    int overlayW = overlayPanel.getWidth();
	    int overlayH = overlayPanel.getHeight();
	    int videoX = windowW - overlayW;
	    int videoY = windowH - overlayH;

	    BufferedImage tempImage = new BufferedImage(windowW, windowH, BufferedImage.TYPE_3BYTE_BGR);
	    videoWindow.paint(tempImage.getGraphics());
	    currImg = tempImage.getSubimage(videoX-9, videoY-9, overlayW-9, overlayH-9);
	    
	    if(trackingEnabled){
	    	Rectangle r = search(IplImage.createFrom(currImg));
			drawOnVideo(r);
	        if(currentFrame >= 0){                
		        prevFrame = currentFrame;
		        currentFrame += (1 + frameSkip);
		        mediaDelegate.setVideoFrame(currentFrame);
	        }   
	    } 
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		JButton source = (JButton) e.getSource();
	    if(source == startBtn && selection != null){
	    	trackingEnabled = true;
			startNewTracker();
	    	currentFrame = mediaDelegate.mapTimeToFrame(mediaDelegate.getVideoTime());
	    	mediaDelegate.setVideoFrame(currentFrame + 1);
	    	startBtn.setEnabled(false);
	    }
	    else if(source == pauseBtn){
	    	trackingEnabled = false;
	    }
	    else if(source == resumeBtn){
	    	mediaDelegate.setVideoFrame(prevFrame);
	    	trackingEnabled = true;
	    }
	    else if(source == saveBtn){
	    	saveSettings();
	    }
	}

    /**
    * Slider moved
    */
	@Override
	public void stateChanged(ChangeEvent e) {
		JSlider source = (JSlider) e.getSource();
	    if (!source.getValueIsAdjusting()) {
	        if(source == moveSlider){
	        	moveThresh = (int)source.getValue();
	        }
	        else if(source == satSlider){
	        	satThresh = (int)source.getValue();
	        }
	        else if(source == skipSlider){
	        	frameSkip = (int)source.getValue();
	        }
	    }
	}

	@Override
	public void bookmarkAction(AnnotationFile arg0, String arg1) {
	}

	@Override
	public void elementChanged(AnnotationFile arg0, AnnContainer arg1,
			AnnElement arg2, AnvilAction arg3) {
	}

	@Override
	public void activeContainerChanged(ContainerChangeEvent e) {
        AnnContainer container = e.getContainer();
        trackingEnabled = false;
        if (container != null) {
	        ActiveTrack = container.longName();
			getTrackSettings();
        }
	}

	@Override
	public void selectedAnnotationFileChanged(AnnotationFileImpl arg0) {
	}

	@Override
	public void selectedElementChanged(SelectionChangeEvent arg0) {
	}

	@Override
	public void mouseClicked(MouseEvent e) {}

	@Override
	public void mouseEntered(MouseEvent e) {}

	@Override
	public void mouseExited(MouseEvent e) {}

	@Override
	public void mousePressed(MouseEvent e) {
        getSelection(0, e.getX(), e.getY());
	}
	@Override
	public void mouseReleased(MouseEvent e) {
        getSelection(1, e.getX(), e.getY());
	}

	@Override
	public void itemStateChanged(ItemEvent e) {
		JCheckBox source = (JCheckBox) e.getItemSelectable();
		if(source == showProjWindow){
			projCanvas.setVisible(source.isSelected());
		}
		else if(source == showSatWindow){
			satCanvas.setVisible(source.isSelected());
		}
	}
}
